package com.imis.base.util.form;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.imis.base.constant.CommonConstant;
import com.imis.base.constant.DataBaseConstant;
import com.imis.base.constant.enums.MatchTypeEnum;
import com.imis.base.constant.enums.QueryRuleEnum;
import com.imis.base.shiro.util.DataAuthorUtils;
import com.imis.base.util.ConvertUtils;
import com.imis.base.util.CurrentUserUtils;
import com.imis.base.util.SpringContextUtils;
import com.imis.base.util.form.model.DataPermissionRuleModel;
import com.imis.base.util.form.model.QueryCondition;
import com.imis.base.util.table.DataBaseTableUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtils;
import org.springframework.util.NumberUtils;

import javax.servlet.http.HttpSession;
import java.beans.PropertyDescriptor;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <p>
 * QueryGenerator<br>
 * 查询生成器
 * </p>
 *
 * @author XinLau
 * @since 2020-03-12
 */
@Slf4j
public class QueryGenerator {

    public static final String SQL_RULES_COLUMN = "SQL_RULES_COLUMN";
    /**
     * 数字类型字段，拼接此后缀 接受多值参数
     */
    private static final String MULTI = "_MultiString";
    /**
     * 排序列
     */
    private static final String ORDER_COLUMN = "column";
    /**
     * 排序方式
     */
    private static final String ORDER_TYPE = "order";

    /**
     * 从 session 中获取变量
     *
     * @param key - Session Key
     * @return String -
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/24 16:44
     */
    private static String getSessionData(String key) {
        // 得到 ${} 后面的值
        String moshi = CommonConstant.EMPTY;
        if (key.contains(CommonConstant.RIGHT_BRACE)) {
            moshi = key.substring(key.indexOf(CommonConstant.RIGHT_BRACE) + 1);
        }
        StringBuilder returnValue = new StringBuilder();
        if (key.contains(CommonConstant.HASH_LEFT_BRACE)) {
            key = key.substring(2, key.indexOf(CommonConstant.RIGHT_BRACE));
        }
        if (StrUtil.isNotEmpty(key)) {
            HttpSession session = SpringContextUtils.getHttpServletRequest().getSession();
            String sessionAttribute = (String) session.getAttribute(key);
            returnValue.append(sessionAttribute);
        }
        // 结果加上 ${} 后面的值
        returnValue.append(moshi);
        return returnValue.toString();
    }

    /**
     * 从当前用户中获取系统变量
     *
     * @param key - 变量名
     * @return String -
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/24 16:44
     */
    private static String getUserSystemData(String key) {
        // #{user_id}%
        String moshi = CommonConstant.EMPTY;
        if (key.contains(CommonConstant.RIGHT_BRACE)) {
            moshi = key.substring(key.indexOf(CommonConstant.RIGHT_BRACE) + 1);
        }
        StringBuilder returnValue = new StringBuilder();
        // 针对特殊标示处理 #{organizationCode}，判断替换
        if (key.contains(CommonConstant.HASH + CommonConstant.RIGHT_BRACE)) {
            key = key.substring(2, key.indexOf(CommonConstant.RIGHT_BRACE) + 1);
        }
        if (key.equals(DataBaseConstant.CREATE_BY) || key.equalsIgnoreCase(DataBaseConstant.CREATE_BY_FIELD)
                || key.equals(DataBaseConstant.UPDATE_BY) || key.equalsIgnoreCase(DataBaseConstant.UPDATE_BY_FIELD)) {
            // 获取当前登录用户编号
            Long userId = CurrentUserUtils.getUserIdFormHttpServletRequest();
            returnValue.append(ConvertUtils.isEmpty(userId) ? StringPool.ZERO : userId);
        } else if (key.equals(DataBaseConstant.ORGANIZATION_CODE) || key.equalsIgnoreCase(DataBaseConstant.ORGANIZATION_CODE_FIELD)) {
            // 替换为系统用户登录所使用的机构编码
            Long organizationId = CurrentUserUtils.getOrganizationIdFormHttpServletRequest();
            returnValue.append(ConvertUtils.isEmpty(organizationId) ? StringPool.ZERO : organizationId);
        } else if (key.equals(DataBaseConstant.CREATE_TIME) || key.equalsIgnoreCase(DataBaseConstant.CREATE_TIME_FIELD)
                || key.equals(DataBaseConstant.UPDATE_TIME) || key.equalsIgnoreCase(DataBaseConstant.UPDATE_TIME_FIELD)) {
            // 替换为当前系统时间（年月日时分秒）
            returnValue.append(LocalDateTime.now());
        } else if (key.equals(DataBaseConstant.PROCESS_STATE) || key.equalsIgnoreCase(DataBaseConstant.PROCESS_STATE_FIELD)) {
            // 流程状态默认值（默认未发起）
            returnValue.append(DataBaseConstant.ONE);
        }
        returnValue.append(moshi);
        return returnValue.toString();
    }

    /**
     * 不可操作字段
     *
     * @param name - 字段名
     * @return Boolean -
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/24 16:44
     */
    private static Boolean judgedIsUselessField(String name) {
        return "class".equals(name) || "ids".equals(name)
                || "page".equals(name) || "rows".equals(name)
                || "sort".equals(name) || "order".equals(name);
    }

    /**
     * 将规则添加到查询包装器
     *
     * @param dataRule     - 数据规则
     * @param name         - 字段名
     * @param propertyType - 字段类型
     * @param queryWrapper - 查询包装器
     * @return null -
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/26 10:03
     */
    private static void addRuleToQueryWrapper(DataPermissionRuleModel dataRule, String name, Class propertyType, QueryWrapper<?> queryWrapper) {
        QueryRuleEnum rule = QueryRuleEnum.getByValue(dataRule.getRuleConditions());
        if (QueryRuleEnum.IN.equals(rule) && !propertyType.equals(String.class)) {
            String[] values = dataRule.getRuleValue().split(CommonConstant.COMMA);
            Object[] objs = new Object[values.length];
            for (int i = 0; i < values.length; i++) {
                objs[i] = NumberUtils.parseNumber(values[i], propertyType);
            }
            addEasyQuery(queryWrapper, name, rule, objs);
        } else {
            if (propertyType.equals(String.class)) {
                addEasyQuery(queryWrapper, name, rule, convertRuleValue(dataRule.getRuleValue()));
            } else if (propertyType.equals(Date.class)) {
                String dateStr = convertRuleValue(dataRule.getRuleValue());
                if (dateStr.length() == 10) {
                    addEasyQuery(queryWrapper, name, rule, ConvertUtils.str2Date(dateStr, DatePattern.NORM_DATE_PATTERN));
                } else {
                    addEasyQuery(queryWrapper, name, rule, ConvertUtils.str2Date(dateStr, DatePattern.NORM_DATETIME_PATTERN));
                }
            } else if (propertyType.equals(LocalDate.class)) {
                String dateStr = convertRuleValue(dataRule.getRuleValue());
                addEasyQuery(queryWrapper, name, rule, LocalDate.parse(dateStr, DateTimeFormatter.BASIC_ISO_DATE));
            } else if (propertyType.equals(LocalDateTime.class)) {
                String dateStr = convertRuleValue(dataRule.getRuleValue());
                addEasyQuery(queryWrapper, name, rule, LocalDateTime.parse(dateStr, DateTimeFormatter.ISO_DATE_TIME));
            } else {
                addEasyQuery(queryWrapper, name, rule, NumberUtils.parseNumber(dataRule.getRuleValue(), propertyType));
            }
        }
    }

    /**
     * 根据规则走不同的查询
     *
     * @param queryWrapper - QueryWrapper
     * @param name         - 字段名字
     * @param rule         - 查询规则
     * @param value        - 查询条件值
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/24 16:44
     */
    private static void addEasyQuery(QueryWrapper<?> queryWrapper, String name, QueryRuleEnum rule, Object value) {
        if (value == null || rule == null || ConvertUtils.isEmpty(value)) {
            return;
        }
        name = ConvertUtils.camelToUnderline(name);
        log.info("--查询规则-->" + name + " " + rule.getValue() + " " + value);
        switch (rule) {
            case GT:
                queryWrapper.gt(name, value);
                break;
            case GE:
                queryWrapper.ge(name, value);
                break;
            case LT:
                queryWrapper.lt(name, value);
                break;
            case LE:
                queryWrapper.le(name, value);
                break;
            case EQ:
                queryWrapper.eq(name, value);
                break;
            case NE:
                queryWrapper.ne(name, value);
                break;
            case IN:
                if (value instanceof String) {
                    queryWrapper.in(name, (Object[]) value.toString().split(CommonConstant.COMMA));
                } else if (value instanceof String[]) {
                    queryWrapper.in(name, (Object[]) value);
                } else {
                    queryWrapper.in(name, value);
                }
                break;
            case LIKE:
                queryWrapper.like(name, value);
                break;
            case LEFT_LIKE:
                queryWrapper.likeLeft(name, value);
                break;
            case RIGHT_LIKE:
                queryWrapper.likeRight(name, value);
                break;
            default:
                log.info("--查询规则未匹配到---");
                break;
        }
    }

    /**
     * 获取日期类型的值
     *
     * @param value - 日期
     * @param rule  - Query 规则
     * @throws ParseException -
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/24 16:44
     */
    private static Date getDateQueryByRule(String value, QueryRuleEnum rule) throws ParseException {
        Date date = null;
        SimpleDateFormat dateFormat = new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
        if (value.length() == 10) {
            if (rule == QueryRuleEnum.GE) {
                // 比较大于
                date = dateFormat.parse(value + " 00:00:00");
            } else if (rule == QueryRuleEnum.LE) {
                // 比较小于
                date = dateFormat.parse(value + " 23:59:59");
            }
            // TODO 日期类型比较特殊 可能 oracle下不一定好使
        }
        if (date == null) {
            date = dateFormat.parse(value);
        }
        return date;
    }

    /**
     * 获取日期类型的值
     *
     * @param value - 日期
     * @param rule  - Query 规则
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/24 16:44
     */
    private static LocalDate getLocalDateQueryByRule(String value, QueryRuleEnum rule) {
        LocalDate date = null;
        if (rule == QueryRuleEnum.GE) {
            // 比较大于
            date = LocalDate.parse(value + " 00:00:00");
        } else if (rule == QueryRuleEnum.LE) {
            // 比较小于
            date = LocalDate.parse(value + " 23:59:59");
        }
        // TODO 日期类型比较特殊 可能 oracle下不一定好使
        return date;
    }

    /**
     * 获取日期类型的值
     *
     * @param value - 日期
     * @param rule  - Query 规则
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/24 16:44
     */
    private static LocalDateTime getLocalDateTimeQueryByRule(String value, QueryRuleEnum rule) {
        LocalDateTime date = null;
        if (rule == QueryRuleEnum.GE) {
            // 比较大于
            date = LocalDateTime.parse(value + " 00:00:00");
        } else if (rule == QueryRuleEnum.LE) {
            // 比较小于
            date = LocalDateTime.parse(value + " 23:59:59");
        }
        // TODO 日期类型比较特殊 可能 oracle下不一定好使
        return date;
    }

    /**
     * 处理查询条件
     *
     * @param queryWrapper - QueryWrapper
     * @param name         - 字段名字
     * @param type         - 字段类型
     * @param value        - 查询规则
     * @param rule         - 查询条件值
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/26 10:58
     */
    private static void addQueryByRule(QueryWrapper<?> queryWrapper, String name, String type, String value, QueryRuleEnum rule) throws ParseException {
        if (ConvertUtils.isNotEmpty(value)) {
            Object temp;
            // 针对数字类型字段，多值查询
            if (value.contains(CommonConstant.COMMA)) {
                temp = value;
                addEasyQuery(queryWrapper, name, rule, temp);
                return;
            }

            switch (type) {
                case "class java.lang.Integer":
                    temp = Integer.parseInt(value);
                    break;
                case "class java.math.BigDecimal":
                    temp = new BigDecimal(value);
                    break;
                case "class java.lang.Short":
                    temp = Short.parseShort(value);
                    break;
                case "class java.lang.Long":
                    temp = Long.parseLong(value);
                    break;
                case "class java.lang.Float":
                    temp = Float.parseFloat(value);
                    break;
                case "class java.lang.Double":
                    temp = Double.parseDouble(value);
                    break;
                case "class java.util.Date":
                    temp = getDateQueryByRule(value, rule);
                    break;
                case "class java.time.LocalDate":
                    temp = getLocalDateQueryByRule(value, rule);
                    break;
                case "class java.time.LocalDateTime":
                    temp = getLocalDateTimeQueryByRule(value, rule);
                    break;
                default:
                    temp = value;
                    break;
            }
            addEasyQuery(queryWrapper, name, rule, temp);
        }
    }

    /**
     * 根据所传的值 转化成对应的比较方式
     * 支持 ><= like in !
     *
     * @param value - 值
     * @return QueryRuleEnum - Query 规则
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/26 10:58
     */
    private static QueryRuleEnum convert2Rule(Object value) {
        // 避免空数据
        if (value == null) {
            return null;
        }
        String stringValue = String.valueOf(value).trim();
        if (stringValue.length() == 0) {
            return null;
        }
        QueryRuleEnum rule = null;
        // TODO 此处规则，只适用于 le lt ge gt
        // step 2 .>= =<
        if (stringValue.length() >= 3) {
            if (DataBaseConstant.SPACE.equals(stringValue.substring(2, 3))) {
                rule = QueryRuleEnum.getByValue(stringValue.substring(0, 2));
            }
        }
        // step 1 .> <
        if (rule == null && stringValue.length() >= 2) {
            if (DataBaseConstant.SPACE.equals(stringValue.substring(1, 2))) {
                rule = QueryRuleEnum.getByValue(stringValue.substring(0, 1));
            }
        }
        // step 3 like
        if (rule == null && stringValue.contains(CommonConstant.ASTERISK)) {
            if (stringValue.startsWith(CommonConstant.ASTERISK) && stringValue.endsWith(CommonConstant.ASTERISK)) {
                rule = QueryRuleEnum.LIKE;
            } else if (stringValue.startsWith(CommonConstant.ASTERISK)) {
                rule = QueryRuleEnum.LEFT_LIKE;
            } else if (stringValue.endsWith(CommonConstant.ASTERISK)) {
                rule = QueryRuleEnum.RIGHT_LIKE;
            }
        }
        // step 4 in
        if (rule == null && stringValue.contains(CommonConstant.COMMA)) {
            // TODO:This in 查询这里应该有个bug  如果一字段本身就是多选 此时用in查询 未必能查询出来
            rule = QueryRuleEnum.IN;
        }
        // step 5 !=
        if (rule == null && stringValue.startsWith(CommonConstant.EXCLAMATION_MARK)) {
            rule = QueryRuleEnum.NE;
        }
        return rule != null ? rule : QueryRuleEnum.EQ;
    }

    /**
     * 替换掉关键字字符
     *
     * @param rule - Query 规则
     * @return value - 查询值
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/26 11:58
     */
    private static Object replaceValue(QueryRuleEnum rule, Object value) {
        if (rule == null) {
            return null;
        }
        if (!(value instanceof String)) {
            return value;
        }
        String val = String.valueOf(value).trim();
        if (rule == QueryRuleEnum.LIKE) {
            value = val.substring(1, val.length() - 1);
        } else if (rule == QueryRuleEnum.LEFT_LIKE || rule == QueryRuleEnum.NE) {
            value = val.substring(1);
        } else if (rule == QueryRuleEnum.RIGHT_LIKE) {
            value = val.substring(0, val.length() - 1);
        } else if (rule == QueryRuleEnum.IN) {
            value = val.split(CommonConstant.COMMA);
        } else {
            // installMyBatisPlusQueryWrapper 组装 SQL 查询条件错误
            if (val.startsWith(rule.getValue())) {
                // TODO 此处逻辑应该注释掉 -> 如果查询内容中带有查询匹配规则符号，就会被截取的（比如：>= 您好）
                value = val.replaceFirst(rule.getValue(), DataBaseConstant.EMPTY);
            } else if (val.startsWith(rule.getCondition() + DataBaseConstant.SPACE)) {
                value = val.replaceFirst(rule.getCondition() + DataBaseConstant.SPACE, DataBaseConstant.EMPTY).trim();
            }
        }
        return value;
    }

    /**
     * 多字段排序
     *
     * @param queryWrapper - QueryWrapper
     * @param parameterMap - request.getParameterMap()
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/26 14:00
     */
    private static void doMultiFieldsOrder(QueryWrapper<?> queryWrapper, Map<String, String[]> parameterMap) {
        String column = null, order = null;
        if (parameterMap != null && parameterMap.containsKey(ORDER_COLUMN)) {
            column = parameterMap.get(ORDER_COLUMN)[0];
        }
        if (parameterMap != null && parameterMap.containsKey(ORDER_TYPE)) {
            order = parameterMap.get(ORDER_TYPE)[0];
        }
        log.debug("排序规则>>列:" + column + ",排序方式:" + order);
        if (ConvertUtils.isNotEmpty(column) && ConvertUtils.isNotEmpty(order)) {
            // 字典字段，去掉字典翻译文本后缀
            assert column != null;
            if (column.endsWith(CommonConstant.DICT_TEXT_SUFFIX)) {
                column = column.substring(0, column.lastIndexOf(CommonConstant.DICT_TEXT_SUFFIX));
            }
            // SQL注入 Check
            ConvertUtils.filterContent(column);
            assert order != null;
            if (order.toUpperCase().contains(DataBaseConstant.SQL_ASC)) {
                queryWrapper.orderByAsc(ConvertUtils.camelToUnderline(column));
            } else {
                queryWrapper.orderByDesc(ConvertUtils.camelToUnderline(column));
            }
        }
    }

    /**
     * 高级查询
     *
     * @param queryWrapper - QueryWrapper
     * @param parameterMap - request.getParameterMap()
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/26 14:00
     */
    private static void doSuperQuery(QueryWrapper<?> queryWrapper, Map<String, String[]> parameterMap) {
        if (parameterMap != null && parameterMap.containsKey(DataBaseConstant.SUPER_QUERY_PARAMS)) {
            String superQueryParams = parameterMap.get(DataBaseConstant.SUPER_QUERY_PARAMS)[0];
            String superQueryMatchType = parameterMap.get(DataBaseConstant.SUPER_QUERY_MATCH_TYPE) != null ? parameterMap.get(DataBaseConstant.SUPER_QUERY_MATCH_TYPE)[0] : MatchTypeEnum.AND.getValue();
            MatchTypeEnum matchType = MatchTypeEnum.getByValue(superQueryMatchType);
            // 高级查询的条件要用括号括起来，防止和用户的其他条件冲突
            try {
                superQueryParams = URLDecoder.decode(superQueryParams, DataBaseConstant.UTF_8);
                List<QueryCondition> conditions = JSON.parseArray(superQueryParams, QueryCondition.class);
                if (conditions == null || conditions.size() == 0) {
                    return;
                }
                log.info("---高级查询参数-->" + conditions);
                queryWrapper.and(andWrapper -> {
                    for (int i = 0; i < conditions.size(); i++) {
                        QueryCondition rule = conditions.get(i);
                        if (ConvertUtils.isNotEmpty(rule.getField())
                                && ConvertUtils.isNotEmpty(rule.getRule())
                                && ConvertUtils.isNotEmpty(rule.getValue())) {
                            log.debug("SuperQuery ==> " + rule);
                            addEasyQuery(andWrapper, rule.getField(), QueryRuleEnum.getByValue(rule.getRule()), rule.getValue());
                            // 如果拼接方式是OR，就拼接OR
                            if (MatchTypeEnum.OR == matchType && i < (conditions.size() - 1)) {
                                andWrapper.or();
                            }
                        }
                    }
                    // return andWrapper;
                });
            } catch (UnsupportedEncodingException e) {
                log.error("高级查询参数转码失败：" + superQueryParams, e);
            } catch (Exception e) {
                log.error("高级查询拼接失败：" + e.getMessage());
                e.printStackTrace();
            }
        }
        log.debug(" superQuery getCustomSqlSegment: " + queryWrapper.getCustomSqlSegment());
    }

    /**
     * 组装 Mybatis-Plus 查询条件<br>
     * 使用此方法 需要有如下几点注意:
     * <ul>
     *     <li>1.使用 QueryWrapper 而非 LambdaQueryWrapper </li>
     *     <li>2.实例化 QueryWrapper 时不可将实体传入参数 </li>
     *     <li>3.也可以不使用这个方法直接调用 {@link #initQueryWrapper}直接获取实例</li>
     * </ul>
     *
     * @param queryWrapper - 条件构造器
     * @param searchEntity - 查询实体
     * @param parameterMap - request.getParameterMap()
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/21 9:27
     */
    private static void installMyBatisPlusQueryWrapper(QueryWrapper<?> queryWrapper, Object searchEntity, Map<String, String[]> parameterMap) {
        /*
         * 注意：权限查询由前端配置数据规则，
         * 当一个人有多个所属部门时候，可以在规则配置包含条件 organizationCode 包含 #{organization_code} 但是不支持在自定义SQL中写 organizationCode in #{organization_code}
         * 当一个人只有一个部门 就直接配置等于条件: organizationCode 等于 #{organization_code} 或者配置自定义SQL: organizationCode = '#{organization_code}'
         */

        // 区间条件组装、模糊查询、高级查询组装、简单排序、权限查询
        PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(searchEntity);
        Map<String, DataPermissionRuleModel> dataPermissionRuleHashMap = getDataPermissionRuleHashMap();
        // 权限规则自定义 SQL 表达式
        for (String column : dataPermissionRuleHashMap.keySet()) {
            if (ConvertUtils.isNotEmpty(column) && column.startsWith(SQL_RULES_COLUMN)) {
                queryWrapper.and(query -> query.apply(getStructuredQueryLanguageRuleValue(dataPermissionRuleHashMap.get(column).getRuleValue())));
            }
        }
        // 实体类属性描述符
        String name, type;
        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            //aliasName = propertyDescriptors[i].getName();  mybatis  不存在实体属性 不用处理别名的情况
            name = propertyDescriptor.getName();
            type = propertyDescriptor.getPropertyType().toString();
            try {
                if (judgedIsUselessField(name) || !PropertyUtils.isReadable(searchEntity, name)) {
                    // 不可操作字段，不可读字段
                    continue;
                }
                // 数据权限查询
                if (dataPermissionRuleHashMap.containsKey(name)) {
                    addRuleToQueryWrapper(dataPermissionRuleHashMap.get(name), name, propertyDescriptor.getPropertyType(), queryWrapper);
                }
                // 添加 判断是否有区间值
                String endValue, beginValue;
                if (parameterMap != null && parameterMap.containsKey(name + DataBaseConstant.SUFFIX_START)) {
                    beginValue = parameterMap.get(name + DataBaseConstant.SUFFIX_START)[0].trim();
                    addQueryByRule(queryWrapper, name, type, beginValue, QueryRuleEnum.GE);
                }
                if (parameterMap != null && parameterMap.containsKey(name + DataBaseConstant.SUFFIX_END)) {
                    endValue = parameterMap.get(name + DataBaseConstant.SUFFIX_END)[0].trim();
                    addQueryByRule(queryWrapper, name, type, endValue, QueryRuleEnum.LE);
                }
                // 多值查询
                if (parameterMap != null && parameterMap.containsKey(name + MULTI)) {
                    endValue = parameterMap.get(name + MULTI)[0].trim();
                    addQueryByRule(queryWrapper, name.replace(MULTI, ""), type, endValue, QueryRuleEnum.IN);
                }
                // 判断单值  参数带不同标识字符串 走不同的查询
                // TODO 这种前后带逗号的支持分割后模糊查询需要否 使多选字段的查询生效
                Object value = PropertyUtils.getSimpleProperty(searchEntity, name);
                if (null != value && value.toString().startsWith(CommonConstant.COMMA) && value.toString().endsWith(CommonConstant.COMMA)) {
                    String multiLikeValue = value.toString().replace(",,", CommonConstant.COMMA);
                    String[] likeValueArray = multiLikeValue.substring(1).split(CommonConstant.COMMA);
                    final String field = ConvertUtils.camelToUnderline(name);
                    if (likeValueArray.length > 1) {
                        queryWrapper.and(query -> {
                            query = query.like(field, likeValueArray[0]);
                            for (int k = 1; k < likeValueArray.length; k++) {
                                query = query.or().like(field, likeValueArray[k]);
                            }
                            // return query;
                        });
                    } else {
                        queryWrapper.and(query -> query.like(field, likeValueArray[0]));
                    }
                } else {
                    // 根据参数值带什么关键字符串判断走什么类型的查询
                    QueryRuleEnum rule = convert2Rule(value);
                    value = replaceValue(rule, value);
                    // add -begin 添加判断为字符串时设为全模糊查询
                    //if( (rule==null || QueryRuleEnum.EQ.equals(rule)) && "class java.lang.String".equals(type)) {
                    // 可以设置左右模糊或全模糊，因人而异
                    //rule = QueryRuleEnum.LIKE;
                    //}
                    // add -end 添加判断为字符串时设为全模糊查询
                    addEasyQuery(queryWrapper, name, rule, value);
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
        // 排序逻辑 处理
        doMultiFieldsOrder(queryWrapper, parameterMap);
        // 高级查询
        doSuperQuery(queryWrapper, parameterMap);
    }

    /**
     * 获取系统数据库类型
     *
     * @return String - 数据库类型
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/20 13:43
     */
    private static String getDataBaseType() {
        String dataBaseType = "";
        try {
            dataBaseType = DataBaseTableUtil.getDataBaseType();
        } catch (SQLException throwable) {
            log.debug(throwable.getMessage(), throwable);
        }
        return dataBaseType;
    }

    /**
     * 获取字段条件值
     *
     * @param value    - 参数值
     * @param isString - 字符串类型标识
     * @return null -
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/26 14:31
     */
    private static String getFieldConditionValue(Object value, Boolean isString) {
        if (isString) {
            String stringValue = value.toString().trim();
            if (stringValue.startsWith(DataBaseConstant.EXCLAMATION_MARK)) {
                stringValue = stringValue.substring(1);
            } else if (stringValue.startsWith(DataBaseConstant.GREATER_THAN_OR_EQUAL_TO)) {
                stringValue = stringValue.substring(2);
            } else if (stringValue.startsWith(DataBaseConstant.LESS_THAN_OR_EQUAL_TO)) {
                stringValue = stringValue.substring(2);
            } else if (stringValue.startsWith(DataBaseConstant.RIGHT_CHEV)) {
                stringValue = stringValue.substring(1);
            } else if (stringValue.startsWith(DataBaseConstant.LEFT_CHEV)) {
                stringValue = stringValue.substring(1);
            }
            if (DataBaseConstant.DB_TYPE_SQL_SERVER.equals(getDataBaseType())) {
                return DataBaseConstant.SPACE + CommonConstant.TO_UPPER_CASE_N + DataBaseConstant.SINGLE_QUOTE + stringValue + DataBaseConstant.SINGLE_QUOTE + DataBaseConstant.SPACE;
            } else {
                return DataBaseConstant.SPACE + DataBaseConstant.SINGLE_QUOTE + stringValue + DataBaseConstant.SINGLE_QUOTE + DataBaseConstant.SPACE;
            }
        } else {
            return String.valueOf(value);
        }
    }

    /**
     * IN 查询
     *
     * @param value    - 参数值
     * @param isString - 字符串类型标识
     * @return null -
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/26 14:31
     */
    private static String getInConditionValue(Object value, Boolean isString) {
        if (isString) {
            String[] temp = value.toString().split(DataBaseConstant.COMMA);
            StringBuilder res = new StringBuilder(CommonConstant.EMPTY);
            for (String string : temp) {
                if (DataBaseConstant.DB_TYPE_SQL_SERVER.equals(getDataBaseType())) {
                    res.append(DataBaseConstant.COMMA + CommonConstant.TO_UPPER_CASE_N + DataBaseConstant.SINGLE_QUOTE).append(string).append(DataBaseConstant.SINGLE_QUOTE);
                } else {
                    res.append(DataBaseConstant.COMMA + DataBaseConstant.SINGLE_QUOTE).append(string).append(DataBaseConstant.SINGLE_QUOTE);
                }
            }
            return DataBaseConstant.LEFT_BRACKET + res.substring(1) + DataBaseConstant.RIGHT_BRACKET;
        } else {
            return DataBaseConstant.LEFT_BRACKET + value + DataBaseConstant.RIGHT_BRACKET;
        }
    }

    /**
     * 模糊查询
     *
     * @param value - 参数值
     * @return String -
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/26 14:53
     */
    private static String getLikeConditionValue(Object value) {
        String stringValue = value.toString().trim();
        if (stringValue.startsWith(DataBaseConstant.ASTERISK) && stringValue.endsWith(DataBaseConstant.ASTERISK)) {
            if (DataBaseConstant.DB_TYPE_SQL_SERVER.equals(getDataBaseType())) {
                return CommonConstant.TO_UPPER_CASE_N + DataBaseConstant.SINGLE_QUOTE + DataBaseConstant.PERCENT + stringValue.substring(1, stringValue.length() - 1) + DataBaseConstant.PERCENT + DataBaseConstant.SINGLE_QUOTE;
            } else {
                return DataBaseConstant.SINGLE_QUOTE + DataBaseConstant.PERCENT + stringValue.substring(1, stringValue.length() - 1) + DataBaseConstant.PERCENT + DataBaseConstant.SINGLE_QUOTE;
            }
        } else if (stringValue.startsWith(DataBaseConstant.ASTERISK)) {
            if (DataBaseConstant.DB_TYPE_SQL_SERVER.equals(getDataBaseType())) {
                return CommonConstant.TO_UPPER_CASE_N + DataBaseConstant.SINGLE_QUOTE + DataBaseConstant.PERCENT + stringValue.substring(1) + DataBaseConstant.SINGLE_QUOTE;
            } else {
                return DataBaseConstant.SINGLE_QUOTE + DataBaseConstant.PERCENT + stringValue.substring(1) + DataBaseConstant.SINGLE_QUOTE;
            }
        } else if (stringValue.endsWith(DataBaseConstant.ASTERISK)) {
            if (DataBaseConstant.DB_TYPE_SQL_SERVER.equals(getDataBaseType())) {
                return CommonConstant.TO_UPPER_CASE_N + DataBaseConstant.SINGLE_QUOTE + stringValue.substring(0, stringValue.length() - 1) + DataBaseConstant.PERCENT + DataBaseConstant.SINGLE_QUOTE;
            } else {
                return DataBaseConstant.SINGLE_QUOTE + stringValue.substring(0, stringValue.length() - 1) + DataBaseConstant.PERCENT + DataBaseConstant.SINGLE_QUOTE;
            }
        } else {
            if (stringValue.contains(DataBaseConstant.PERCENT)) {
                final boolean hasSingleQuote = stringValue.startsWith(DataBaseConstant.SINGLE_QUOTE) && stringValue.endsWith(DataBaseConstant.SINGLE_QUOTE);
                if (DataBaseConstant.DB_TYPE_SQL_SERVER.equals(getDataBaseType())) {
                    if (hasSingleQuote) {
                        return CommonConstant.TO_UPPER_CASE_N + stringValue;
                    } else {
                        return CommonConstant.TO_UPPER_CASE_N + DataBaseConstant.SINGLE_QUOTE + stringValue + DataBaseConstant.SINGLE_QUOTE;
                    }
                } else {
                    if (hasSingleQuote) {
                        return stringValue;
                    } else {
                        return DataBaseConstant.SINGLE_QUOTE + stringValue + DataBaseConstant.SINGLE_QUOTE;
                    }
                }
            } else {
                if (DataBaseConstant.DB_TYPE_SQL_SERVER.equals(getDataBaseType())) {
                    return CommonConstant.TO_UPPER_CASE_N + DataBaseConstant.SINGLE_QUOTE + DataBaseConstant.PERCENT + stringValue + DataBaseConstant.PERCENT + DataBaseConstant.SINGLE_QUOTE;
                } else {
                    return DataBaseConstant.SINGLE_QUOTE + DataBaseConstant.PERCENT + stringValue + DataBaseConstant.PERCENT + DataBaseConstant.SINGLE_QUOTE;
                }
            }
        }
    }

    /**
     * 获取查询条件
     *
     * @param rule     - Query 规则
     * @param field    - 字段
     * @param value    - 参数值
     * @param isString - 字符串类型标识
     * @return String -
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/26 14:17
     */
    private static String getSingleStructuredQueryLanguageByRule(final QueryRuleEnum rule, final String field, final Object value, final Boolean isString) {
        String res;
        switch (rule) {
            case GT:
            case GE:
            case LT:
            case LE:
            case EQ:
                res = field + rule.getValue() + getFieldConditionValue(value, isString);
                break;
            case NE:
                res = field + DataBaseConstant.SPACE + DataBaseConstant.LEFT_CHEV + DataBaseConstant.RIGHT_CHEV + DataBaseConstant.SPACE + getFieldConditionValue(value, isString);
                break;
            case IN:
                res = field + DataBaseConstant.SQL_IN + getInConditionValue(value, isString);
                break;
            case LIKE:
            case LEFT_LIKE:
            case RIGHT_LIKE:
                res = field + DataBaseConstant.SQL_LIKE + getLikeConditionValue(value);
                break;
            default:
                res = field + DataBaseConstant.SPACE + DataBaseConstant.EQUALS + DataBaseConstant.SPACE + getFieldConditionValue(value, isString);
                break;
        }
        return res;
    }

    /**
     * 获取查询条件构造器 QueryWrapper 实例 通用查询条件已被封装完成
     *
     * @param searchEntity - 查询实体
     * @param parameterMap - request.getParameterMap()
     * @return QueryWrapper - 条件构造器实例
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/21 9:22
     */
    public static <T> QueryWrapper<T> initQueryWrapper(T searchEntity, Map<String, String[]> parameterMap) {
        long start = System.currentTimeMillis();
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        installMyBatisPlusQueryWrapper(queryWrapper, searchEntity, parameterMap);
        log.debug("--- 查询条件构造器初始化完成,耗时:" + (System.currentTimeMillis() - start) + "毫秒 ---");
        return queryWrapper;
    }

    /**
     * 获取请求对应的数据权限规则
     *
     * @return Map<String, DataPermissionRuleModel>
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/24 16:08
     */
    public static Map<String, DataPermissionRuleModel> getDataPermissionRuleHashMap() {
        Map<String, DataPermissionRuleModel> dataPermissionRuleHashMap = new HashMap<>(16);
        // TODO:This 数据权限规则需要重构
        List<DataPermissionRuleModel> permissionRuleModelList = DataAuthorUtils.loadDataSearchConditionList();
        if (permissionRuleModelList != null && permissionRuleModelList.size() > 0) {
            if (permissionRuleModelList.get(0) == null) {
                return dataPermissionRuleHashMap;
            }
            for (DataPermissionRuleModel dataPermissionRuleModel : permissionRuleModelList) {
                String column = dataPermissionRuleModel.getRuleColumn();
                if (QueryRuleEnum.SQL_FRAGMENT.getValue().equals(dataPermissionRuleModel.getRuleConditions())) {
                    column = SQL_RULES_COLUMN + dataPermissionRuleModel.getId();
                }
                dataPermissionRuleHashMap.put(column, dataPermissionRuleModel);
            }
        }
        return dataPermissionRuleHashMap;
    }

    /**
     * 获取 SQL 中的 #{key} 这个 key 组成的 HashSet
     *
     * @param structuredQueryLanguage - SQL语句
     * @return Set<String> -
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/24 16:28
     */
    public static Set<String> getStructuredQueryLanguageRuleParams(String structuredQueryLanguage) {
        Set<String> paramsHashSet = new HashSet<>();
        if (ConvertUtils.isNotEmpty(structuredQueryLanguage)) {
            Pattern pattern = Pattern.compile("\\#\\{\\w+\\}");
            Matcher matcher = pattern.matcher(structuredQueryLanguage);
            while (matcher.find()) {
                String key = matcher.group();
                paramsHashSet.add(key.substring(key.indexOf(DataBaseConstant.LEFT_BRACE) + 1, key.indexOf(DataBaseConstant.RIGHT_BRACE)));
            }
        }
        return paramsHashSet;
    }

    /**
     * 调整 SQL 规则值
     *
     * @param ruleValue - 规则值
     * @return String - 加工后的 SQL
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/24 16:08
     */
    public static String convertRuleValue(String ruleValue) {
        String sessionAttribute = getSessionData(ruleValue);
        if (ConvertUtils.isEmpty(sessionAttribute)) {
            sessionAttribute = getUserSystemData(ruleValue);
        }
        return ConvertUtils.isNotEmpty(sessionAttribute) ? sessionAttribute : ruleValue;
    }

    /**
     * 获取 SQL 规则值
     *
     * @param structuredQueryLanguageRuleValueRule - SQL 规则值
     * @return String - 加工后的 SQL
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/24 16:08
     */
    public static String getStructuredQueryLanguageRuleValue(String structuredQueryLanguageRuleValueRule) {
        try {
            Set<String> paramsHashSet = getStructuredQueryLanguageRuleParams(structuredQueryLanguageRuleValueRule);
            for (String params : paramsHashSet) {
                String tempValue = convertRuleValue(params);
                structuredQueryLanguageRuleValueRule = structuredQueryLanguageRuleValueRule.replace("#{" + params + "}", tempValue);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return structuredQueryLanguageRuleValueRule;
    }

    /**
     * 去掉值前后单引号
     *
     * @param ruleValue -
     * @return String -  去掉值前后单引号后
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/26 14:07
     */
    public static String trimSingleQuote(String ruleValue) {
        if (ConvertUtils.isEmpty(ruleValue)) {
            return CommonConstant.EMPTY;
        }
        if (ruleValue.startsWith(CommonConstant.SINGLE_QUOTE)) {
            ruleValue = ruleValue.substring(1);
        }
        if (ruleValue.endsWith(CommonConstant.SINGLE_QUOTE)) {
            ruleValue = ruleValue.substring(0, ruleValue.length() - 1);
        }
        return ruleValue;
    }

    /**
     * 获取查询条件
     *
     * @param field    - 字段
     * @param alias    - 别名
     * @param value    - 参数值
     * @param isString - 字符串类型标识
     * @return String -  查询条件
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/26 14:07
     */
    public static String getSingleQueryConditionStructuredQueryLanguage(String field, String alias, Object value, Boolean isString) {
        if (value == null) {
            return CommonConstant.EMPTY;
        }
        field = alias + ConvertUtils.camelToUnderline(field);
        QueryRuleEnum rule = QueryGenerator.convert2Rule(value);
        return getSingleStructuredQueryLanguageByRule(rule, field, value, isString);
    }

    /*************************************************************************************************/


    /**
     * 根据权限相关配置生成相关的SQL 语句
     *
     * @param clazz -
     * @return String -
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static String installAuthJdbc(final Class<?> clazz) {
        StringBuilder sb = new StringBuilder();
        //权限查询
        Map<String, DataPermissionRuleModel> ruleMap = getDataPermissionRuleHashMap();
        PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(clazz);
        String sqlAnd = DataBaseConstant.SQL_AND;
        for (String c : ruleMap.keySet()) {
            if (ConvertUtils.isNotEmpty(c) && c.startsWith(SQL_RULES_COLUMN)) {
                sb.append(sqlAnd).append(getStructuredQueryLanguageRuleValue(ruleMap.get(c).getRuleValue()));
            }
        }
        String name;
        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            name = propertyDescriptor.getName();
            if (judgedIsUselessField(name)) {
                continue;
            }
            if (ruleMap.containsKey(name)) {
                DataPermissionRuleModel dataRule = ruleMap.get(name);
                QueryRuleEnum rule = QueryRuleEnum.getByValue(dataRule.getRuleConditions());
                Class propType = propertyDescriptor.getPropertyType();
                boolean isString = propType.equals(String.class);
                Object value;
                if (isString) {
                    value = convertRuleValue(dataRule.getRuleValue());
                } else {
                    value = NumberUtils.parseNumber(dataRule.getRuleValue(), propType);
                }
                String filedSql = getSingleStructuredQueryLanguageByRule(rule, ConvertUtils.camelToUnderline(name), value, isString);
                sb.append(sqlAnd).append(filedSql);
            }
        }
        log.info("QUERY AUTH SQL IS:" + sb);
        return sb.toString();
    }

    /**
     * 根据权限相关配置 组装mp需要的权限
     *
     * @param queryWrapper -
     * @param clazz        -
     * @return
     */
    public static void installAuthMplus(final QueryWrapper<?> queryWrapper, final Class<?> clazz) {
        //权限查询
        Map<String, DataPermissionRuleModel> ruleMap = getDataPermissionRuleHashMap();
        PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(clazz);
        for (String c : ruleMap.keySet()) {
            if (ConvertUtils.isNotEmpty(c) && c.startsWith(SQL_RULES_COLUMN)) {
                queryWrapper.and(query -> query.apply(getStructuredQueryLanguageRuleValue(ruleMap.get(c).getRuleValue())));
            }
        }
        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            // 字段名
            String name = propertyDescriptor.getName();
            if (judgedIsUselessField(name)) {
                continue;
            }
            if (ruleMap.containsKey(name)) {
                addRuleToQueryWrapper(ruleMap.get(name), name, propertyDescriptor.getPropertyType(), queryWrapper);
            }
        }
    }

    /**
     * 转换 SQL 中的系统变量
     *
     * @param structuredQueryLanguage - SQL
     * @return String - SQL 规则值
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/10/29 14:21
     */
    public static String convertSystemVariables(String structuredQueryLanguage) {
        return getStructuredQueryLanguageRuleValue(structuredQueryLanguage);
    }

    /**
     * 获取所有配置的权限 返回 SQL 字符串 不受字段限制 配置什么就拿到什么
     *
     * @return structuredQueryLanguage - SQL
     */
    public static String getAllConfigAuth() {
        StringBuilder structuredQueryLanguage = new StringBuilder();
        // 权限查询
        Map<String, DataPermissionRuleModel> ruleMap = getDataPermissionRuleHashMap();
        for (String field : ruleMap.keySet()) {
            DataPermissionRuleModel dataRule = ruleMap.get(field);
            String ruleValue = dataRule.getRuleValue();
            if (ConvertUtils.isEmpty(ruleValue)) {
                continue;
            }
            if (ConvertUtils.isNotEmpty(field) && field.startsWith(SQL_RULES_COLUMN)) {
                structuredQueryLanguage.append(DataBaseConstant.SQL_AND).append(getStructuredQueryLanguageRuleValue(ruleValue));
            } else {
                boolean isString = false;
                ruleValue = ruleValue.trim();
                if (ruleValue.startsWith(CommonConstant.SINGLE_QUOTE) && ruleValue.endsWith(CommonConstant.SINGLE_QUOTE)) {
                    isString = true;
                    ruleValue = ruleValue.substring(1, ruleValue.length() - 1);
                }
                QueryRuleEnum rule = QueryRuleEnum.getByValue(dataRule.getRuleConditions());
                String value = convertRuleValue(ruleValue);
                String filedSql = getSingleStructuredQueryLanguageByRule(rule, field, value, isString);
                structuredQueryLanguage.append(DataBaseConstant.SQL_AND).append(filedSql);
            }
        }
        log.info("QUERY AUTH SQL IS : " + structuredQueryLanguage);
        return structuredQueryLanguage.toString();
    }

}
